<template>
  <PageWrapper>
    <!-- 笔记 -->
    <CollapseContainer class="mt-5" title="文档">
      <markdown-viewer :value="getDoc()" />
    </CollapseContainer>

    <CollapseContainer class="mt-5" title="watch-ref">
      <ol>
        <li> 原始对象:{{ person }} <br /> </li>
        <li>
          --监听基本类型属性 person.id:{{ person.id }}
          <Button @click="changePersonId">修改 person.id</Button>
        </li>
        <li>
          --监听对象类型属性 person.address:{{ person.address }}
          <Button @click="changePersonAddress">修改 person.address</Button>
          <Button @click="changePersonCity">修改 person.address.city</Button>
        </li>
      </ol>
      <template #action>
        <Icon icon="ant-design:code-outlined" class="mr-1" :size="26" @click="openSource('深度引用', getSource())" />
      </template>
    </CollapseContainer>

    <!-- 源码组件 -->
    <SourceDrawer ref="sourceDrawer" />
  </PageWrapper>
</template>
<script lang="ts" setup>
  import { CollapseContainer } from '@/components/Container';
  import { MarkdownViewer } from '@/components/Markdown';
  import { PageWrapper } from '@/components/Page';
  import { Button } from '@/components/Button';
  import SourceDrawer from '@/learn/SourceDrawer.vue';
  import { Icon } from '@/components/Icon';
  import { ref, reactive, watch } from 'vue';
  import { useMessage } from '@/hooks/web/useMessage';

  const { createMessage } = useMessage();

  // 定义子组件引用
  let sourceDrawer = ref<any>(null);
  function openSource(title: string, content: string) {
    sourceDrawer.value.open({ title, content, width: '60%' });
  }

  // 使用 ref 或 reactive 修饰都可以，没有区别
  let person = reactive<any>({ id: 1001, name: 'lisi', address: { province: '河南', city: '郑州' } });

  function changePersonId() {
    person.id += 10;
  }
  function changePersonCity() {
    person.address.city += '*-';
  }
  function changePersonAddress() {
    person.address = { province: '河北', city: '石家庄' };
  }

  let stopWatchId = watch(
    () => person.id,
    (newVal: number, oldVal) => {
      createMessage.info('监听person.id: 上升到 1100 后停止监听，当前值:' + newVal);
      if (newVal > 1100) {
        createMessage.error('停止监听');
        stopWatchId();
      }
    },
  );

  watch(
    () => person.address,
    (newVal) => {
      // 监视对象时，默认只有对象地址发生变更时，才会触发。需要手动设置 deep:true
      createMessage.info('监听person.address深度监视: ' + JSON.stringify(newVal));
    },
    { deep: true },
  );
</script>

<script lang="ts">
  function getDoc() {
    return `
### getter 函数: 监视响应式对象(ref/reactive)的具体属性 
* 在实际应用中，常见的应用是：监控某个对象中的属性变化，然后做一些事情。
* 监视对象中的属性时，必须通过 getter 函数来实现。因为 watch 只能监视 ref 和 reactive 类型
* 根据 getter 函数返回的类型有所不同:
  * 基本类型: 可以时刻监听
  * 对象类型: 只能监听到地址引用变更，如果要同时监听对象属性变更，则需要手动开启 deep:true   
* 注意事项:
  * getter 返回的一定要是响应式对象内部的属性 
`;
  }

  function getSource() {
    return `
\`\`\`html
<template>
  <CollapseContainer class="mt-5" title="watch-ref">
    <ol>
      <li> 原始对象:{{ person }} <br /> </li>
      <li>
        --监听基本类型属性 person.id:{{ person.id }}
        <Button @click="changePersonId">修改 person.id</Button>
      </li>
      <li>
        --监听对象类型属性 person.address:{{ person.address }}
        <Button @click="changePersonAddress">修改 person.address</Button>
        <Button @click="changePersonCity">修改 person.address.city</Button>
      </li>
    </ol>
    <template #action>
      <Icon icon="ant-design:code-outlined" class="mr-1" :size="26" @click="openSource('深度引用', getSource())" />
    </template>
  </CollapseContainer>
</template>

\<script lang="ts" setup\>
// 使用 ref 或 reactive 修饰都可以，没有区别
  let person = reactive<any>({ id: 1001, name: 'lisi', address: { province: '河南', city: '郑州' } });

  function changePersonId() {
    person.id += 10;
  }
  function changePersonCity() {
    person.address.city += '*-';
  }
  function changePersonAddress() {
    person.address = { province: '河北', city: '石家庄' };
  }

  let stopWatchId = watch(
    () => person.id,
    (newVal: number, oldVal) => {
      createMessage.info('监听person.id: 上升到 1100 后停止监听，当前值:' + newVal);
      if (newVal > 1100) {
        createMessage.error('停止监听');
        stopWatchId();
      }
    },
  );

  watch(
    () => person.address,
    (newVal) => {
      // 监视对象时，默认只有对象地址发生变更时，才会触发。需要手动设置 deep:true
      createMessage.info('监听person.address深度监视: ' + JSON.stringify(newVal));
    },
    { deep: true },
  );
\</script\>
\`\`\`
`;
  }
</script>

<style lang="less" scoped>
  button {
    margin-left: 5px;
  }
</style>
